昨天把一輪的結果寫成 results.yaml,六個狀態各司其職,那一包分出 4 個 pass、6 個 fail、1 個 inconclusive、1 個 anomaly。
但 status 只回答了一半的問題。它說的是「這筆判不判得動」,沒說「這筆帳算誰的」。同樣是 fail,可能是產品寫錯,也可能是測試環境掛了、帳號被別人鎖了,或者根本是我自己操作順序弄反。
今天處理後面那一半。素材是 2026-07-26 到 07-30 十二輪的狀態檔,加上 output/known-false-positives.yaml。
回到昨天那筆「console 有 4 則 error,卻判 pass」。那 4 則逐則對得上:
GET /users/me 回的 401POST /users/login 回的 401如果每則紅字都當缺陷,那一輪就產出 4 張廢單。而那一輪的檢查點總共才 4 筆。
誤報的代價不是「多一張單」。多一張單只是浪費工程師十分鐘。真正的代價是下一次沒人看你的單 —— 一旦你的單被退過幾次,退你的人就會養成先假設你搞錯的習慣,而那時候你手上真的有一張重要的單也沒用了。
所以今天要立的規矩只有一句:
一個異常有很多種原因,只有一種是產品缺陷。不分類就報,等於開一間誤報工廠。
配一句方法:依證據判類,不靠猜,每一次判類都要指得出依據哪一條 evidence。
category 這個欄位一筆都沒有這一節是今天最誠實的部分,而且證物是我自己的紀錄。
classify-anomaly 這支 skill 規定判類要寫回 finding,四個欄位:category、confidence、basis、next_step。規格寫得清清楚楚。
然後我去查了 output/ 底下所有狀態檔。
十二輪,category 這個欄位一筆都沒有。
實際跑出來的是另一套詞彙。20260730-toolshop-bughunt-gaps/candidates.yaml 裡直接寫:
verdict: BUG
oracle_used: ...
basis: ...
confidence: ...
factors: ...
從 anomaly 一步跳到 BUG,中間那一步整個被跳過了。
後果不是「分類錯」。分類錯至少還留得下一個可以吵的答案;跳過分類的後果是**「為什麼判它是產品的鍋」這句話查不到**。basis 那欄有寫,但寫的是「為什麼它像 bug」,不是「為什麼排除了環境、測資、我自己」。
這正是今天要擋的事,而擋不住的證據就是我自己的十二輪紀錄。跳過分類不會有人來罵你,它只會在第四週變成一堆退不回去的單。
修法也很清楚,而且跟 Day 11、Day 12 是同一條:把 category 變成 results.yaml 的必填欄位,缺了就不准往下。靠形狀強制,不靠記性。
classify-anomaly 分七類。但這張表真正的欄位不是「它是什麼」,是**「它把責任指向誰」**:
| category | 責任在 | 能往下開單嗎 |
|---|---|---|
| product-bug | 產品 | 可以(續走 test-oracle) |
| environment | 服務/基礎設施 | 否 |
| test-data | 帳號、髒資料、前一步污染 | 否 |
| operation-artifact | 我自己(順序錯、前置沒做、選錯元素) | 否 |
| flaky | 間歇重現 | 否,記重現率 |
| known-issue | 命中已知清單 | 否 |
| needs-investigation | 證據不夠歸類 | 否,回去補證據 |
七類裡只有一類能往下。所以這張表的功能不是分類學,是一道閘:它擋掉的那六類,每一類都是一張本來會被開出去的廢單。
口訣先給:服務層壞了是 environment,帳號或資料壞了是 test-data,我自己搞出來的是 operation-artifact。
口訣好記,難的是排除。看兩個實跑的例子。
423 Locked 為什麼判 test-data現象是 POST /users/login 回 423,UI 顯示「Account locked, too many failed attempts」。

畫面訊息與 API 狀態碼一致。產品這裡沒做錯任何事,難的是判斷這筆帳算誰的。
要判它是 test-data,得先把另外三類逐一排掉:
423 是應用層給的正確語意,不是連線失敗。results.yaml 裡是 pass。三類都排掉,才輪到 test-data,依據寫「共享 demo 帳號被其他 session 觸發鎖定」。
這裡有一個關鍵值得點出來:能排除 operation-artifact,是因為手上有「我這輪做了什麼」的完整紀錄。沒有 Day 8 到 Day 11 那包證據,這一筆只能寫 needs-investigation。留證跟分類不是兩件事,前者是後者的前提。
現象是第一次 snapshot 只讀到「Reltded products」,主商品資訊卡整塊不見。
但同一時間 GET /products/1 回 200,而且全頁截圖證實畫面完整渲染 —— 標題、圖片、價格、規格全都在。

同一時刻的全頁截圖。snapshot 讀不到的東西,截圖上好好地在那裡。判 operation-artifact 靠的就是這種「另一種觀測方式」的旁證。
判 operation-artifact:那是 Angular 渲染與 accessibility tree 快照之間的時間差,是我的觀測時機問題,不是產品的。
這一筆在 Day 12 的狀態是 inconclusive,今天給它 category。兩層詞彙各司其職:status 說「判不判得動」,category 說「這筆帳算誰的」。同一筆東西可以是「判不動」而且「算我自己頭上」。
在旁證:服務狀態、我的操作紀錄、另一種觀測方式的結果。只盯著畫面看,這三類永遠分不開。
要誠實講一件事:這十二輪裡沒有一筆真的判成 environment。 全部都在 demo 站上跑,服務一次都沒掛過。所以上面那個口訣裡,environment 是唯一沒有實例的一類,它的判準目前只是紙上談兵。
購物車數量填 -5,畫面 Total 顯示 -$70.75。
這一筆算誰的?光看畫面答不出來,要看你多做的那一步:
| 多做的那一步 | 結論 |
|---|---|
| reload 後回復成 1、變更沒觸發寫入呼叫 | 前端零驗證,後端從未收到,問題在前端 |
| reload 後負數還在、確實寫進後端 | 後端也沒驗證,嚴重度完全不同 |
實測是前者。判類依據寫成一句:「變更未觸發寫入呼叫、reload 後回復 1(從未寫入後端)→ 問題在前端,排除環境。」
這一節要立的規矩是:basis 不是把現象再說一次,是寫你排除了什麼、憑哪條證據排除。
「畫面顯示負數」不是 basis,那是現象。「reload 後回復成 1」才是 basis,因為它排掉了一整條分支。
分類不是逐筆做完就算。收工前還要橫著看一遍。
規則是:多筆共用同一個錯誤簽章(同一個逾時、同一個 5xx、同一個連線錯),很可能是 environment 或整層事件,歸一類,不要逐筆當產品缺陷。
素材就是第一節那 4 則 401:其中三則指向同一件事(未登入所以沒有 session),第四則是前端把它印出來。一件事,不是四件。
反過來也要警告:不能把不同簽章硬併成一類,那會漏掉真的缺陷。判準是簽章,不是「看起來很像」。
這一條目前也還沒真的執行過。上面那 4 則 401 是我事後查檔案對出來的,不是當時跑的動作。
這一節最容易被略過,但實務上最有用。
output/known-false-positives.yaml 現在兩筆,都在 2026-07-27 拍板:
| pattern | scope | 判成 |
|---|---|---|
GET /users/me 回 401,且發生在未登入頁面 |
anonymous-only | 非缺陷(前端把它記成 error) |
POST /users/login 回 423(共享測試帳號) |
test-account only | test-data,已驗證為暫時性鎖定 |
每筆四個欄位:pattern、scope、reason、decided_by 加日期。
decided_by 是重點。 門檻寫得很硬:進這份清單等於已經有人拍板。還沒人決定的(needs-spec)不准放進來,否則這份清單會變成「我覺得應該不是問題」的垃圾桶。
為什麼值得專講?因為這是唯一會讓下一輪自動閉嘴的東西。其他分類結果都只影響當下那一輪,只有這份清單跨輪生效。
scope 那一欄不要省。同一個 401 在未登入頁是預期,在已登入頁就是缺陷。沒有 scope 的清單會把真缺陷一起消音。
這一類同樣還沒有實跑示範:清單有兩筆,但還沒有留下「下一輪撞到它、自動閉嘴」的紀錄。
一個異常先問它算誰的帳,七類裡只有 product-bug 能往下;最難分的環境、測資、我自己三類,判準都不在畫面上而在旁證,所以 basis 要寫「我排除了什麼、憑哪條證據」,不是把現象再講一次。逐筆判完還要橫著看一次,同簽章的歸成一件。判完寫回該筆 finding 四個欄位:category、confidence、basis、next_step;flaky 必記重現率,needs-investigation 必寫還缺什麼證據,不准只寫「待查」就放著。
一個異常
│
▼
這筆帳算誰的?(看旁證)
│
┌──────────┬──────────┬─┴────────┬──────────┬──────────┐
▼ ▼ ▼ ▼ ▼ ▼
environment test-data operation flaky known-issue needs-
服務掛了 帳號/髒資料 artifact 間歇重現 命中清單 investigation
被別人鎖 我自己弄的 自動閉嘴 證據不夠
│ │ │ │ │ │
└──────────┴──────────┴────┬─────┴──────────┴──────────┘
│
這六類都不能開單
│
▼
product-bug
(只有這一類)
│
▼
收工前橫著看一次:同簽章歸一件
│
▼
寫回 finding:category/confidence
basis/next_step
basis = 我排除了什麼,憑哪條證據
│
▼
往下交給 test-oracle
誤報的代價不是多一張單,是下一次沒人看你的單,四則 401 全開成缺陷,那一輪就是四張廢單配四個檢查點。basis 寫的是排除不是現象,「畫面顯示負數」不算依據,「reload 後回復成 1」才算。而規格寫了不等於做得到:十二輪紀錄裡 category 一筆都沒有,靠記性守不住的規矩要靠形狀守,把它變成必填欄位,缺了就不准往下。
分類完,手上剩下的 product-bug 才有資格往下。
但「往下」不是直接開單。下一關是:你能不能把它寫成一份別人照著就能重現的報告 —— 而且那個別人拿不到你的推理,跟 Day 11 的交棒標準是同一條。
明天寫第一份 Bug Report。
skills/observe/classify-anomaly/ - 七類與四個欄位的真檔output/known-false-positives.yaml - 第六節那兩筆